`include "defines.v"

module clint (//Core-Local Interruptor
    input  wire clk,
    input  wire rst,
    
    input  wire [`REG_BUS]               clint_w_data_i,
    input  wire                          clint_w_en_i,
    input  wire [`RAM_ADDR_WIDTH - 1: 0] clint_addr_i,
    input  wire                          clint_valid_i,
    output wire                          clint_ready_o,
    
    output reg [`REG_BUS]                clint_r_data_o,

    output wire                          timer_interrupt
);
    // mtime >= mtimecmp时，产生计时器中断，mip的MTIP位置1；

    // Machine time register
    reg [`REG_BUS]      mtime;
    wire[`REG_BUS]      mtime_add;
    wire[`REG_BUS]      mtime_value;

    // Machine time compare register
    reg [`REG_BUS]      mtimecmp;
    wire[`REG_BUS]      mtimecmp_value;

    assign mtime_add = mtime + 1;
    assign mtime_value    = (clint_valid_i == 1'b1) && (clint_w_en_i == 1'b1) && (clint_addr_i == `RAM_ADDR_WIDTH'h200bff8) ? clint_w_data_i : mtime_add;
    
    assign mtimecmp_value = (clint_valid_i == 1'b1) && (clint_w_en_i == 1'b1) && (clint_addr_i == `RAM_ADDR_WIDTH'h2004000) ? clint_w_data_i : mtimecmp;

    assign timer_interrupt= mtime >= mtimecmp ? 1'b1 : 1'b0;

    always @(posedge clk)begin
        if ( rst == 1'b1 ) begin
            mtime       <= `ZERO_WORD;
            mtimecmp    <= `ZERO_WORD;
        end
        else begin
            mtime       <= mtime_value;
            mtimecmp    <= mtimecmp_value;
        end
    end

    always @(*) begin
        if (clint_valid_i == 1'b1 && clint_w_en_i == 1'b0) begin
            case (clint_addr_i)
                `RAM_ADDR_WIDTH'h200bff8: begin
                    clint_r_data_o = mtime;
                end 
                `RAM_ADDR_WIDTH'h2004000: begin
                    clint_r_data_o = mtimecmp;
                end
                default: begin
                    clint_r_data_o = `ZERO_WORD;
                end
            endcase
        end else begin
            clint_r_data_o = `ZERO_WORD; 
        end
    end

    assign clint_ready_o = clint_valid_i;
    // // 通过 MMIO 打印
    // always @(posedge clk) 
    // begin
    //         if((clint_valid_i == 1'b1) && (clint_w_en_i == 1'b1) && (clint_addr_i == 64'ha10003F8))
    //         begin
    //             $write("%c", clint_w_data_i[7:0]);
    //         end
    // end
endmodule
